unit BD_PgmCalMT_Aux;

interface
uses Winapi.Windows, Winapi.Messages,System.Classes, System.SysUtils, Vcl.Forms,
BD_UUT, StrUtils,Vcl.Dialogs;

const
  MEMBANNER = '--------------------------------------------------------------------------------';

type TLogData = (
  ID,
  WorkOrderNumber,
  SerialNumber,
  PassFailStatus,
  FlashOnOff,
  RetestStatus,
  Bat1Meas,
  Bat2Meas,
  PresMeasZeroPres,
  PresA2DAvgCalcZeroPres,
  PresA2DMaxCalcZeroPres,
  PresA2DMinCalcZeroPres,
  PresA2DDiffCalcZeroPres,
  Stage1A2DAvgCalcZeroPres,
  Stage1A2DMaxCalcZeroPres,
  Stage1A2DMinCalcZeroPres,
  Stage1A2DDiffCalcZeroPres,
  PresLeak1Meas,
  PresLeak2Meas,
  PresLeakCalc,
  PresMeasFullPres,
  PresA2DAvgCalcFullPres,
  PresA2DMaxCalcFullPres,
  PresA2DMinCalcFullPres,
  PresA2DDiffCalcFullPres,
  Stage1A2DAvgCalcFullPres,
  Stage1A2DMaxCalcFullPres,
  Stage1A2DMinCalcFullPres,
  Stage1A2DDiffCalcFullPres,
  PresMeasReturnZero,
  PresA2DAvgCalcReturnZero,
  PresA2DMaxCalcReturnZero,
  PresA2DMinCalcReturnZero,
  PresA2DDiffCalcReturnZero,
  Stage1A2DAvgCalcReturnZero,
  Stage1A2DMaxCalcReturnZero,
  Stage1A2DMinCalcReturnZero,
  Stage1A2DDiffCalcReturnZero,
  Bat3Meas,
  A1Calc,
  C1Calc,
  HysteresisCalc,
  VersionUUT,
  WRPresA2DMaxCnfg,
  WRPresA2DMinCnfg,
  WRBgnInflCnfg,
  WRDsplMaxAtmBarCnfg,
  WRDsplMaxPSICnfg,
  WRDsplMinCnfg,
  WREndInflCnfg,
  WRGelCnfg,
  WRMaxAllowedInflsCnfg,
  WRStage1A2DMaxAllowedCnfg,
  WRStage1A2DMinAllowedCnfg,
  WROcclusionPresCnfg,
  WROcclusionTimeCnfg,
  WRAllowUnitsCnfg,
  WRLedDimFreqCnfg,
  WRLedDimPresResetCnfg,
  WRLedOffPresResetCnfg,
  WRLedNormalFreqCnfg,
  WROffTimeCnfg,
  WROnUnitsCnfg,
  WRPrsrValCnfg,
  WRRZWindowCnfg,
  WRStabilizingPresCnfg,
  WRLedDimActivationTimeCnfg,
  WRLedOffActivationTimeCnfg,
  WRAutoOffActivationTimeCnfg,
  WRTotStage1A2DSamplesCnfg,
  WRTotPresSamplesCnfg,
  WRZWindowCnfg,
  WRPresBlinkDutyCycleCnfg,
  WRVersionCnfg,
  WRTotalPresA2DReadsPerPresCnfg,
  WRFlashOnOffCnfg
);
 //TCfgFileParams holds the values from the ECN controlled config file which will be used during the calibration
//process as range checks to ensure the UUT is reading/sending valid information.
type TCfgFileParams = record
  BatLowCnfg: Double;
  BatHighCnfg: Double;
  SystemPresZeroPresLowCnfg: Double;
  SystemPresZeroPresHighCnfg: Double;
  PresA2DLowZeroPresCnfg: Word;
  PresA2DHighZeroPresCnfg: Word;
  PresA2DDiffMaxCnfg: Word;
  Stage1A2DLowZeroPresCnfg: Word;
  Stage1A2DHighZeroPresCnfg: Word;
  Stage1A2DdiffmaxCnfg: Word;
  LeakLowCnfg: Double;
  LeakHighCnfg: Double;
  PresA2DLowFullPresCnfg: Word;
  PresA2DHighFullPresCnfg: Word;
  Stage1A2DLowFullPresCnfg: Word;
  Stage1A2DHighFullPresCnfg: Word;
  SystemPresFullPresLowCnfg: Double;
  SystemPresFullPresHighCnfg: Double;
  SlopeMaxCnfg: Double;
  PresA2DRailedMinCnfg: Word;
  PresA2DRailedMaxCnfg: Word;
  HysteresisMaxCnfg: Double;
  PresA2DMaxCnfg: Word;
  PresA2DMinCnfg: Word;
  BgnInflCnfg: SmallInt;
  DsplMaxAtmBarCnfg: SmallInt;
  DsplMaxPSICnfg: SmallInt;
  DsplMinCnfg: SmallInt;
  EndInflCnfg: SmallInt;
  GelCnfg: SmallInt;
  MaxAllowedInflsCnfg: Word;
  Stage1A2DMaxAllowedCnfg: Word;
  Stage1A2DMinAllowedCnfg: Word;
  OcclusionPresCnfg: Word;
  OcclusionTimeCnfg: Word;
  AllowUnitsCnfg: byte;
  LedDimFreqCnfg: byte;
  LedDimPresResetCnfg: byte;
  LedOffPresResetCnfg: byte;
  LedNormalFreqCnfg: byte;
  OffTimeCnfg: byte;
  OnUnitsCnfg: byte;
  PrsrValCnfg: byte;
  RZWindowCnfg: byte;
  StabilizingPresCnfg: byte;
  LedDimActivationTimeCnfg: byte;
  LedOffActivationTimeCnfg: byte;
  AutoOffActivationtimeCnfg: byte;
  TotStage1A2DSamplesCnfg: byte;
  TotPresSamplesCnfg: byte;
  ZWindowCnfg: byte;
  PresBlinkDutyCycleCnfg: byte;
  VersionCnfg: byte;
  TotalPresA2DReadsPerPresCnfg: Word;
  FlashOnOffCnfg: byte;
end;

procedure InitParamGrid;
procedure UpdateParamGrid;
procedure CreateLogRecord;   //creates a record of the current UUT following pgm/cal.
procedure LoadCfgParams(var cfg: TCfgFileParams);   //Loads the configuration files parameters
procedure MemMsg(msg: string);    //adds message to the GUI memo with banner.
procedure FullResetTester;   //resets the Test head relays, lights, and the GUI
procedure ResetGui;     //clears memo, terminal, and grids
//'Check' Procedures- the following procedures perform checks on the data
//and parameters from the calibration process to ensure they are within spec, and stop the
//calibration process and report if not
procedure CheckBattV(mode: TBattMeas);     //Verify Battery Voltage in range
procedure CheckADValues(seq: TCalSequence);    //Check A/D parameters
procedure CheckSysPressure(seq: TCalSequence);   //Check System Pressure
procedure CheckLeakTest(state: TLeakState);    //Check leak rate of UUT while at full pressure
procedure CheckFinalCalcs;       //verify A1, C1 values and hysterisis
procedure CheckSN;   //verify that the SN is stored correctly in the UUT


implementation
uses BDPgmCalMTMain;
(*******************************************************************************
  InitParamGrid: Initializes the fixed rows and colums of the UUT Parameters grid.
********************************************************************************)
procedure InitParamGrid;
var
  FixedRowInfo: TStringList; i, MaxWidth: Integer;
begin
  FixedRowInfo := TStringList.Create;
  try
    //Load in the 32 parameter names that are programmed in the UUT during calibration
    if FileExists(ExtractFilePath(Application.ExeName)+'BD_Parameter_List.txt',False) then
      begin
        FixedRowInfo.LoadFromFile(ExtractFilePath(Application.ExeName)+'BD_Parameter_List.txt' );
        frmMain.Memo1.Lines.Add('Loading UUT Parameter labels.');
      end
      else
        begin
          frmMain.Memo1.Lines.Add('Unable to find file '+ ExtractFilePath(Application.ExeName)+'BD_Parameter_List.txt');
          Exit;
        end;
    //initialize the parameter grid label column with the parameter names
    frmMain.sgUUTParameters.RowCount := FixedRowInfo.Count - 1;
    //Display the parameters in the label column of the grid, and find the widest string of all params
    MaxWidth := 0;   //initialize
    for i := 0 to FixedRowInfo.Count-1 do
      begin
        frmMain.sgUUTParameters.Cells[0,i] := FixedRowInfo[i];
        if frmMain.sgUUTParameters.Canvas.TextWidth(frmMain.sgUUTParameters.Cells[0,i]) > MaxWidth then
          MaxWidth := frmMain.sgUUTParameters.Canvas.TextWidth(frmMain.sgUUTParameters.Cells[0,i]);
      end;
    //Now set the column 0 (parameter lables) width the match the widest parameter string
    frmMain.sgUUTParameters.ColWidths[0] := MaxWidth + 28;
    frmMain.sgUUTParameters.ColWidths[1] := frmMain.sgUUTParameters.Width - frmMain.sgUUTParameters.ColWidths[0] - 4;
    //frmMain.sgUUTParameters.Height := (frmMain.sgUUTParameters.RowCount * frmMain.sgUUTParameters.RowHeights[0]) +
                                      //(frmMain.sgUUTParameters.RowCount * 1);
  finally
    FixedRowInfo.Free;
  end;
end;

(*******************************************************************************
  UpdateParamGrid: Writes the paramater values that will be sent to the UUT
                   to the Parameter Grid.
********************************************************************************)
procedure UpdateParamGrid;
var
  i, j: integer; pB: pByte;
begin
  i := 1;
  j := 0;
  //first, deal with the double byte parameters
  while i <= 29 do
  begin
    pB := @UUT.bParams[i+1];
    frmMain.sgUUTParameters.Cells[1,j] := UUT.ExtractWord(pB).ToString;
    inc(i,2);
    inc(j,1);
  end;
  i := 31;     //force i to the start of the single byte params.
  while i < High(UUT.bParams) do
  begin
    frmMain.sgUUTParameters.Cells[1,j] := (UUT.bParams[i]).ToString;
    inc(i);
    inc(j);
  end;
end;

(******************************************************************************
  CreateLogRecord: Generates a log record for the current UUT upon successful
                   programming and calibration, and adds the recored to the
                   log file.
******************************************************************************)
procedure CreateLogRecord;
var i: Integer; FName, tmpStr: string; RecList: TStringList;
begin
//first, try to locate a log file for the current record. If it doesn't exist,
//then create a new file name.
  RecList := TStringList.Create;
  FName := frmMain.edWorkOrder.Text + '.txt';
  if FileExists(FName) then
    try
      RecList.LoadFromFile(FName);
    except
      MemMsg('Unable to open log file.');
      Exit;
    end
    else
      begin
        if FileExists('LogFileHdr.txt') then
          begin
            try
              RecList.LoadFromFile('LogFileHdr.txt');
            except
              MemMsg('Error opening log header file.');
            end;
          end
          else
            MemMsg('Log header file (LogFileHdr.txt) not found.');
      end;
  //Now clear the array of any previous values
  for i := Low(UUT.TestLog) to High(UUT.TestLog) do
    UUT.TestLog[i] := '';
  UUT.TestLog[Ord(ID)] := frmMain.edSN.Text;
  UUT.TestLog[Ord(WorkOrderNumber)] := frmMain.edWorkOrder.Text;
  UUT.TestLog[Ord(SerialNumber)] := UUT.SNStr;
  if UUT.TestStatus then
    UUT.TestLog[Ord(PassFailStatus)] := 'PASS' else
      UUT.TestLog[Ord(PassFailStatus)] := 'FALSE';
  UUT.TestLog[Ord(FlashOnOff)] := 'ON';
  UUT.TestLog[Ord(RetestStatus)] := '0';    //no retest enabled currently
  UUT.TestLog[Ord(Bat1Meas)] := UUT.BatMeasPreProg.ToString(ffFixed,15,3);
  UUT.TestLog[Ord(Bat2Meas)] := UUT.BatMeasStartCal.ToString(ffFixed,15,3);
  UUT.TestLog[Ord(PresMeasZeroPres)] := UUT.PresMeasZeroPres.ToString(ffFixed,15,3);
  UUT.TestLog[Ord(PresA2DAvgCalcZeroPres)] := UUT.ZeroVals.PresADAvg.ToString;
  UUT.TestLog[Ord(PresA2DMaxCalcZeroPres)] := UUT.ZeroVals.PresADMax.ToString;
  UUT.TestLog[Ord(PresA2DMinCalcZeroPres)] := UUT.ZeroVals.PresADMin.ToString;
  UUT.TestLog[Ord(PresA2DDiffCalcZeroPres)] := UUT.ZeroVals.PresADDiffCalc.toString;
  UUT.TestLog[Ord(Stage1A2DAvgCalcZeroPres)] := UUT.ZeroVals.Stage1Avg.ToString;
  UUT.TestLog[Ord(Stage1A2DMaxCalcZeroPres)] := UUT.ZeroVals.Stage1Max.ToString;
  UUT.TestLog[Ord(Stage1A2DMinCalcZeroPres)] := UUT.ZeroVals.Stage1Min.ToString;
  UUT.TestLog[Ord(Stage1A2DDiffCalcZeroPres)] := UUT.ZeroVals.Stage1DiffCalc.toString;
  UUT.TestLog[Ord(PresLeak1Meas)] := UUT.PressLeak1Meas.ToString(ffFixed, 15, 3);
  UUT.TestLog[Ord(PresLeak2Meas)] := UUT.PressLeak2Meas.ToString(ffFixed,15,3);
  UUT.TestLog[Ord(PresLeakCalc)] := (UUT.PressLeak1Meas-UUT.PressLeak2Meas).ToString(ffFixed,15,3);
  UUT.TestLog[Ord(PresMeasFullPres)] := UUT.PresMeasFullPres.ToString(ffFixed,15,3);
  UUT.TestLog[Ord(PresA2DAvgCalcFullPres)] := UUT.MaxVals.PresADAvg.ToString;
  UUT.TestLog[Ord(PresA2DMaxCalcFullPres)] := UUT.MaxVals.PresADMax.ToString;
  UUT.TestLog[Ord(PresA2DMinCalcFullPres)] := UUT.MaxVals.PresADMin.ToString;
  UUT.TestLog[Ord(PresA2DDiffCalcFullPres)] := UUT.MaxVals.PresADDiffCalc.ToString;
  UUT.TestLog[Ord(Stage1A2DAvgCalcFullPres)] := UUT.MaxVals.Stage1Avg.ToString;
  UUT.TestLog[Ord(Stage1A2DMaxCalcFullPres)] := UUT.MaxVals.Stage1Max.ToString;
  UUT.TestLog[Ord(Stage1A2DMinCalcFullPres)] := UUT.MaxVals.Stage1Min.ToString;
  UUT.TestLog[Ord(Stage1A2DDiffCalcFullPres)] := UUT.MaxVals.Stage1DiffCalc.ToString;
  UUT.TestLog[Ord(PresMeasReturnZero)] := UUT.PresMeasReturnZero.ToString(ffFixed,15,3);
  UUT.TestLog[Ord(PresA2DAvgCalcReturnZero)] := UUT.RTZVals.PresADAvg.ToString;
  UUT.TestLog[Ord(PresA2DMaxCalcReturnZero)] := UUT.RTZVals.PresADMax.ToString;
  UUT.TestLog[Ord(PresA2DMinCalcReturnZero)] := UUT.RTZVals.PresADMin.ToString;
  UUT.TestLog[Ord(PresA2DDiffCalcReturnZero)] := UUT.RTZVals.PresADDiffCalc.ToString;
  UUT.TestLog[Ord(Stage1A2DAvgCalcReturnZero)] := UUT.RTZVals.Stage1Avg.ToString;
  UUT.TestLog[Ord(Stage1A2DMaxCalcReturnZero)] := UUT.RTZVals.Stage1Max.ToString;
  UUT.TestLog[Ord(Stage1A2DMinCalcReturnZero)] := UUT.RTZVals.Stage1Min.ToString;
  UUT.TestLog[Ord(Stage1A2DDiffCalcReturnZero)] := UUT.RTZVals.Stage1DiffCalc.ToString;
  UUT.TestLog[Ord(Bat3Meas)] := UUT.BatMeasEndCal.ToString(ffFixed,15,3);
  UUT.TestLog[Ord(A1Calc)] := UUT.A1Calc.ToString(ffFixed,15,3);
  UUT.TestLog[Ord(C1Calc)] := UUT.C1Calc.ToString(ffFixed,15,3);
  UUT.TestLog[Ord(HysteresisCalc)] := UUT.HysteresisCalc.ToString(ffFixed,15,3);
  UUT.TestLog[Ord(VersionUUT)] := UUT.VersionUUT.ToString;
  UUT.TestLog[Ord(WRPresA2DMaxCnfg)] := cfgParams.PresA2DMaxCnfg.ToString;
  UUT.TestLog[Ord(WRPresA2DMinCnfg)] := cfgParams.PresA2DMinCnfg.ToString;
  UUT.TestLog[Ord(WRBgnInflCnfg)] := cfgParams.BgnInflCnfg.ToString();
  UUT.TestLog[Ord(WRDsplMaxAtmBarCnfg)] := cfgParams.DsplMaxAtmBarCnfg.ToString;
  UUT.TestLog[Ord(WRDsplMaxPSICnfg)] := cfgParams.DsplMaxPSICnfg.ToString;
  UUT.TestLog[Ord(WRDsplMinCnfg)] := cfgParams.DsplMinCnfg.ToString;
  UUT.TestLog[Ord(WREndInflCnfg)] := cfgParams.EndInflCnfg.ToString;
  UUT.TestLog[Ord(WRGelCnfg)] := cfgParams.GelCnfg.ToString;
  UUT.TestLog[Ord(WRMaxAllowedInflsCnfg)] := cfgParams.MaxAllowedInflsCnfg.ToString;
  UUT.TestLog[Ord(WRStage1A2DMaxAllowedCnfg)] := cfgParams.Stage1A2DMaxAllowedCnfg.ToString;
  UUT.TestLog[Ord(WRStage1A2DMinAllowedCnfg)] := cfgParams.Stage1A2DMinAllowedCnfg.ToString;
  UUT.TestLog[Ord(WROcclusionPresCnfg)] := cfgParams.OcclusionPresCnfg.ToString;
  UUT.TestLog[Ord(WROcclusionTimeCnfg)] := cfgParams.OcclusionTimeCnfg.ToString;
  UUT.TestLog[Ord(WRAllowUnitsCnfg)] :=  cfgParams.AllowUnitsCnfg.ToString;
  UUT.TestLog[Ord(WRLedDimFreqCnfg)] := cfgParams.LedDimFreqCnfg.ToString;
  UUT.TestLog[Ord(WRLedDimPresResetCnfg)] := cfgParams.LedDimPresResetCnfg.ToString;
  UUT.TestLog[Ord(WRLedOffPresResetCnfg)] := cfgParams.LedOffPresResetCnfg.ToString;
  UUT.TestLog[Ord(WRLedNormalFreqCnfg)] := cfgParams.LedNormalFreqCnfg.ToString;
  UUT.TestLog[Ord(WROffTimeCnfg)] := cfgParams.OffTimeCnfg.ToString;
  UUT.TestLog[Ord(WROnUnitsCnfg)] := cfgParams.OnUnitsCnfg.ToString;
  UUT.TestLog[Ord(WRPrsrValCnfg)] := cfgParams.PrsrValCnfg.ToString;
  UUT.TestLog[Ord(WRRZWindowCnfg)] := cfgParams.RZWindowCnfg.ToString;
  UUT.TestLog[Ord(WRStabilizingPresCnfg)] := cfgParams.StabilizingPresCnfg.ToString;
  UUT.TestLog[Ord(WRLedDimActivationTimeCnfg)] := cfgParams.LedDimActivationTimeCnfg.ToString;
  UUT.TestLog[Ord(WRLedOffActivationTimeCnfg)] := cfgParams.LedOffActivationTimeCnfg.ToString;
  UUT.TestLog[Ord(WRAutoOffActivationTimeCnfg)] := cfgParams.AutoOffActivationtimeCnfg.ToString;
  UUT.TestLog[Ord(WRTotStage1A2DSamplesCnfg)] := cfgParams.TotStage1A2DSamplesCnfg.ToString;
  UUT.TestLog[Ord(WRTotPresSamplesCnfg)] := cfgParams.TotPresSamplesCnfg.ToString;
  UUT.TestLog[Ord(WRZWindowCnfg)] := cfgParams.ZWindowCnfg.ToString;
  UUT.TestLog[Ord(WRPresBlinkDutyCycleCnfg)] := cfgParams.PresBlinkDutyCycleCnfg.ToString;
  UUT.TestLog[Ord(WRVersionCnfg)] := cfgParams.VersionCnfg.ToString;
  UUT.TestLog[Ord(WRTotalPresA2DReadsPerPresCnfg)] := cfgParams.TotalPresA2DReadsPerPresCnfg.ToString;
  UUT.TestLog[Ord(WRFlashOnOffCnfg)] := cfgParams.FlashOnOffCnfg.ToString;
  if (UUT.TestStatus) then
    begin
      for i := Low(UUT.TestLog) to High(UUT.TestLog)-1 do
        tmpStr := tmpStr + UUT.TestLog[i] +',';
      tmpStr := tmpStr + UUT.TestLog[High(UUT.TestLog)];  //no comma after last entry
    end
    else
      begin
        for i := Low(UUT.TestLog) to Ord(VersionUUT) do
        tmpStr := tmpStr + UUT.TestLog[i] +',';
        for i := Ord(WRPresA2DMaxCnfg) to High(UUT.TestLog)-1 do
           tmpStr := tmpStr + '-,';
        tmpStr := tmpStr + '-';  //no comma after last entry
      end;
  RecList.Add(tmpStr);
  try
    RecList.SaveToFile(FName);
  except
    MemMsg('Unable to save log file to '+FName);
  end;
  RecList.Free;
end;

(******************************************************************************
  LoadCfgParams: Loads fixed values from ECN controlled cfg file, will be
                 replaced by TIniFile load method in the future.
******************************************************************************)
procedure LoadCfgParams(var cfg: TCfgFileParams);
var
  ParamList: TStringList;  i, idx: Integer;
begin
  ParamList := TStringList.Create;
  if FileExists(ExtractFilePath(Application.ExeName)+'BD_Config.txt') then
    try
      ParamList.LoadFromFile(ExtractFilePath(Application.ExeName)+'BD_Config.txt');
      for i := 0 to ParamList.Count-1 do
        begin
          idx := PosEx(',',ParamList[i],1);     //find the comma separator
          //Now copy only the value portion of string back to the list
         ParamList[i] := copy(ParamList[i],idx+1, Length(ParamList[i])-idx);
        end;
    except
      ShowMessage('Unable to open configuration file.');
      ParamList.Free;
    end
  else
    begin
      ShowMessage('Unable to find configuration file.');
      ParamList.Free;
    end;
  try
    cfg.BatLowCnfg := ParamList[0].ToDouble;
    cfg.BatHighCnfg := ParamList[1].ToDouble;
    cfg.SystemPresZeroPresLowCnfg := ParamList[2].ToDouble;
    cfg.SystemPresZeroPresHighCnfg := ParamList[3].ToDouble;
    cfg.PresA2DLowZeroPresCnfg := Word(ParamList[4].toInteger);
    cfg.PresA2DHighZeroPresCnfg := Word(ParamList[5].toInteger);
    cfg.PresA2DDiffMaxCnfg := Word(ParamList[6].toInteger);
    cfg.Stage1A2DLowZeroPresCnfg := Word(ParamList[7].toInteger);
    cfg.Stage1A2DHighZeroPresCnfg := Word(ParamList[8].toInteger);
    cfg.Stage1A2DdiffmaxCnfg := Word(ParamList[9].toInteger);
    cfg.LeakLowCnfg := ParamList[10].ToDouble;
    cfg.LeakHighCnfg := ParamList[11].ToDouble;
    cfg.PresA2DLowFullPresCnfg := Word(ParamList[12].toInteger);
    cfg.PresA2DHighFullPresCnfg := Word(ParamList[13].toInteger);
    cfg.Stage1A2DLowFullPresCnfg := Word(ParamList[14].toInteger);
    cfg.Stage1A2DHighFullPresCnfg := Word(ParamList[15].toInteger);
    cfg.SystemPresFullPresLowCnfg := ParamList[16].ToDouble;
    cfg.SystemPresFullPresHighCnfg := ParamList[17].ToDouble;
    cfg.SlopeMaxCnfg := ParamList[18].ToDouble;
    cfg.PresA2DRailedMinCnfg := Word(ParamList[19].toInteger);;
    cfg.PresA2DRailedMaxCnfg := Word(ParamList[20].toInteger);
    cfg.HysteresisMaxCnfg := ParamList[21].ToDouble;
    cfg.PresA2DMaxCnfg := Word(ParamList[22].toInteger);
    cfg.PresA2DMinCnfg := Word(ParamList[23].toInteger);
    cfg.BgnInflCnfg := SmallInt(ParamList[24].toInteger);
    cfg.DsplMaxAtmBarCnfg := SmallInt(ParamList[25].toInteger);
    cfg.DsplMaxPSICnfg := SmallInt(ParamList[26].toInteger);
    cfg.DsplMinCnfg := SmallInt(ParamList[27].toInteger);
    cfg.EndInflCnfg := SmallInt(ParamList[28].toInteger);
    cfg.GelCnfg := SmallInt(ParamList[29].toInteger);
    cfg.MaxAllowedInflsCnfg := Word(ParamList[30].toInteger);
    cfg.Stage1A2DMaxAllowedCnfg := Word(ParamList[31].toInteger);
    cfg.Stage1A2DMinAllowedCnfg := Word(ParamList[32].toInteger);
    cfg.OcclusionPresCnfg := Word(ParamList[33].toInteger);
    cfg.OcclusionTimeCnfg := Word(ParamList[34].toInteger);
    cfg.AllowUnitsCnfg := Byte(ParamList[35].toInteger);
    cfg.LedDimFreqCnfg := Byte(ParamList[36].toInteger);
    cfg.LedDimPresResetCnfg := Byte(ParamList[37].toInteger);
    cfg.LedOffPresResetCnfg := Byte(ParamList[38].toInteger);
    cfg.LedNormalFreqCnfg := Byte(ParamList[39].toInteger);
    cfg.OffTimeCnfg := Byte(ParamList[40].toInteger);
    cfg.OnUnitsCnfg := Byte(ParamList[41].toInteger);
    cfg.PrsrValCnfg := Byte(ParamList[42].toInteger);
    cfg.RZWindowCnfg := Byte(ParamList[43].toInteger);
    cfg.StabilizingPresCnfg := Byte(ParamList[44].toInteger);
    cfg.LedDimActivationTimeCnfg := Byte(ParamList[45].toInteger);
    cfg.LedOffActivationTimeCnfg := Byte(ParamList[46].toInteger);
    cfg.AutoOffActivationtimeCnfg := Byte(ParamList[47].toInteger);
    cfg.TotStage1A2DSamplesCnfg := Byte(ParamList[48].toInteger);
    cfg.TotPresSamplesCnfg := Byte(ParamList[49].toInteger);
    cfg.ZWindowCnfg := Byte(ParamList[50].toInteger);
    cfg.PresBlinkDutyCycleCnfg := Byte(ParamList[51].toInteger);
    cfg.VersionCnfg := Byte(ParamList[52].toInteger);
    cfg.TotalPresA2DReadsPerPresCnfg := Word(ParamList[53].toInteger);
    cfg.FlashOnOffCnfg := Byte(ParamList[54].toInteger);
  except
    ShowMessage('Error loading config file params into cfg record.');
  end;
  if Assigned(ParamList) then
    ParamList.Free;
end;

(******************************************************************************
  MemMsg: Adds a message to the main GUI memo with top and bottom banner
******************************************************************************)
procedure MemMsg(msg: string);
begin
  frmMain.Memo1.Lines.Add(MEMBANNER);
  frmMain.Memo1.Lines.Add(msg);
  frmMain.Memo1.Lines.Add(MEMBANNER);
end;

(******************************************************************************
  CheckBattV: Verify that the battery voltage measurement are within spec.
******************************************************************************)
procedure CheckBattV(mode: TBattMeas);
var
  EM: string;
begin
  EM := '';   //initialize
  case mode of
    bvPreProg:
      begin
        if not (UUT.BatMeasPreProg >= cfgParams.BatLowCnfg) and
               (UUT.BatMeasPreProg <= cfgParams.BatHighCnfg) then
               EM:= EM + 'Pre-Program battery voltage out of range: '+
                          UUT.BatMeasPreProg.ToString(ffFixed,15,3);
      end;
    bvStartCal:
       begin
        if not (UUT.BatMeasStartCal >= cfgParams.BatLowCnfg) and
               (UUT.BatMeasStartCal <= cfgParams.BatHighCnfg) then
               EM:= EM + 'Start of Calibration battery voltage out of range: '+
                          UUT.BatMeasStartCal.ToString(ffFixed,15,3);
      end;
    bvEndCal:
      begin
        if not (UUT.BatMeasEndCal >= cfgParams.BatLowCnfg) and
               (UUT.BatMeasEndCal <= cfgParams.BatHighCnfg) then
               EM:= EM + 'End of Calibration battery voltage out of range: '+
                          UUT.BatMeasEndCal.ToString(ffFixed,15,3);
      end;
  end;
  if EM <> '' then
    begin
      UUT.PassFailStatus := 'FAIL';    //There was an error, so CAL fails.
      UUT.UUTReady := False;  //Need to set this to communicate back to thread that UUT is no longer ready.
      MemMsg('CALIBRATION FAILED- Error(s) occured: '+#13 + EM);
      frmMain.sbStatus.Panels[1].Text := 'Calilbration Failed.';
      frmMain.ConfigCalAccess;    //UUT status has changed, so update buttons accordingly.
    end;
end;

(******************************************************************************
 CheckSystemPressure: Verify that the measured pressure values applied by the
                      system are within specificiation.
******************************************************************************)
procedure CheckSysPressure(seq: TCalSequence);
var
  EM: string;
begin
  EM := '';   //initialize
  case seq of
    csCaptureZero:
      begin
        if not (UUT.PresMeasZeroPres >= cfgParams.SystemPresZeroPresLowCnfg) and
                (UUT.PresMeasZeroPres <= cfgParams.SystemPresZeroPresHighCnfg) then
          EM := EM + 'Zero System Pressure out of range: '+
                      UUT.PresMeasZeroPres.ToString(ffFixed,15,3);
      end;
    csCaptureMax:
      begin
        if not (UUT.PresMeasFullPres >= cfgParams.SystemPresFullPresLowCnfg) and
                (UUT.PresMeasFullPres <= cfgParams.SystemPresFullPresHighCnfg) then
          EM := EM + 'Full System Pressure out of range: '+
                      UUT.PresMeasFullPres.ToString(ffFixed,15,3);
      end;
    csCaptureRTZ:
      begin
        if not (UUT.PresMeasZeroPres >= cfgParams.SystemPresZeroPresLowCnfg) and
                (UUT.PresMeasZeroPres <= cfgParams.SystemPresZeroPresHighCnfg) then
          EM := EM + 'RTZ System Pressure out of range: '+
                      UUT.PresMeasZeroPres.ToString(ffFixed,15,3);
      end;
  end;
  if EM <> '' then
    begin
      UUT.PassFailStatus := 'FAIL';    //There was an error, so CAL fails.
      UUT.UUTReady := False;  //Need to set this to communicate back to thread that UUT is no longer ready.
      MemMsg('CALIBRATION FAILED- Error(s) occured: '+#13 + EM);
      frmMain.sbStatus.Panels[1].Text := 'Calilbration Failed.';
      frmMain.ConfigCalAccess;    //UUT status has changed, so update buttons accordingly.
      frmMain.cbHighPress.Checked := False;
      frmMain.cbVent.Checked := False;
    end;
end;


(******************************************************************************
 CheckADValues: Verify that the A-D readings are within specificiation.
******************************************************************************)
procedure CheckADValues(seq: TCalSequence);
var
  EM: string;
begin
  EM := '';   //initialize
  case seq of
    csCaptureZero:
      begin
        UUT.ZeroVals.PresADDiffCalc := UUT.ZeroVals.PresADMax - UUT.ZeroVals.PresADMin;   //calc delta.
        UUT.ZeroVals.Stage1DiffCalc := UUT.ZeroVals.Stage1Max - UUT.ZeroVals.Stage1Min;   //calc delta.
        if not(UUT.ZeroVals.PresADMin >= cfgParams.PresA2DLowZeroPresCnfg) then  //check min within range
          EM:=EM+ 'PresADMin out of range: '+ UUT.ZeroVals.PresADMin.ToString + #13;
        if not(UUT.ZeroVals.PresADMax <= cfgParams.PresA2DHighZeroPresCnfg) then //check within max range
          EM:=EM+ 'PresADMax out of range: '+ UUT.ZeroVals.PresADMax.ToString + #13;
        if not(UUT.ZeroVals.PresADDiffCalc <= cfgParams.PresA2DDiffMaxCnfg)then //difference calc in range
          EM:=EM+ 'PresADDiffCalc out of range: '+ UUT.ZeroVals.PresADDiffCalc.ToString + #13;
        if not(UUT.ZeroVals.Stage1Min >= cfgParams.Stage1A2DLowZeroPresCnfg)then //check min within range
          EM:=EM+ 'Stage1Min out of range: '+ UUT.ZeroVals.Stage1Min.ToString + #13;
        if not(UUT.ZeroVals.Stage1Max <= cfgParams.Stage1A2DHighZeroPresCnfg)then //check max within range
          EM:=EM+ 'Stage1Max out of range: '+ UUT.ZeroVals.Stage1Max.ToString + #13;
        if not(UUT.ZeroVals.Stage1DiffCalc <= cfgParams.Stage1A2DdiffmaxCnfg)then //check diff in range
          EM:=EM+ 'Stage1DiffCalc out of range: '+ UUT.ZeroVals.Stage1DiffCalc.ToString + #13;
      end;
    csCaptureMax:
      begin
        UUT.MaxVals.PresADDiffCalc := UUT.MaxVals.PresADMax - UUT.MaxVals.PresADMin;  //calc delta.
        UUT.MaxVals.Stage1DiffCalc := UUT.MaxVals.Stage1Max - UUT.MaxVals.Stage1Min;   //calc delta.
        if not(UUT.MaxVals.PresADMin >= cfgParams.PresA2DLowFullPresCnfg)then  //check min within range
          EM:=EM+ 'PresADMin out of range: '+ UUT.MaxVals.PresADMin.ToString + #13;
        if not(UUT.MaxVals.PresADMax <= cfgParams.PresA2DHighFullPresCnfg)then //check max within range
          EM:=EM+ 'PresADMax out of range: '+ UUT.MaxVals.PresADMax.ToString + #13;
        if not(UUT.MaxVals.PresADDiffCalc <= cfgParams.PresA2DDiffMaxCnfg)then //difference calc in range
          EM:=EM+ 'PresADDiffCalc out of range: '+ UUT.MaxVals.PresADDiffCalc.ToString + #13;
        if not(UUT.MaxVals.Stage1Min >= cfgParams.Stage1A2DLowFullPresCnfg)then //check min within range
          EM:=EM+ 'Stage1Min out of range: '+ UUT.MaxVals.Stage1Min.ToString + #13;
        if not(UUT.MaxVals.Stage1Max >= cfgParams.Stage1A2DHighFullPresCnfg)then //check max within range
          EM:=EM+ 'Stage1Max out of range: '+ UUT.MaxVals.Stage1Max.ToString + #13;
        if not(UUT.MaxVals.Stage1DiffCalc<= cfgParams.Stage1A2DdiffmaxCnfg)then //delta calc in range
          EM:=EM+ 'Stage1DiffCalc out of range: '+ UUT.MaxVals.Stage1DiffCalc.ToString + #13;
      end;
    csCaptureRTZ:
      begin
        UUT.RTZVals.PresADDiffCalc := UUT.RTZVals.PresADMax - UUT.RTZVals.PresADMin;  //calc delta.
        UUT.RTZVals.Stage1DiffCalc := UUT.RTZVals.Stage1Max - UUT.RTZVals.Stage1Min;   //calc delta.
        if not(UUT.RTZVals.PresADMin >= cfgParams.PresA2DLowZeroPresCnfg)then  //check min within range
          EM:=EM+ 'PresADMin out of range: '+ UUT.RTZVals.PresADMin.ToString + #13;
        if not(UUT.RTZVals.PresADMax <= cfgParams.PresA2DHighZeroPresCnfg)then //check max within range
          EM:=EM+ 'PresADMax out of range: '+ UUT.RTZVals.PresADMax.ToString + #13;
        if not(UUT.RTZVals.PresADDiffCalc <= cfgParams.PresA2DDiffMaxCnfg)then //difference calc in range
          EM:=EM+ 'PresADDiffCalc out of range: '+ UUT.RTZVals.PresADDiffCalc.ToString + #13;
        if not(UUT.RTZVals.Stage1Min >= cfgParams.Stage1A2DLowZeroPresCnfg)then //check min within range
          EM:=EM+ 'Stage1Min out of range: '+ UUT.RTZVals.Stage1Min.ToString + #13;
        if not(UUT.RTZVals.Stage1Max >= cfgParams.Stage1A2DHighZeroPresCnfg)then //check max within range
          EM:=EM+ 'Stage1Max out of range: '+ UUT.RTZVals.Stage1Max.ToString + #13;
        if not(UUT.RTZVals.Stage1DiffCalc <= cfgParams.Stage1A2DdiffmaxCnfg)then //delta calc in range
          EM:=EM+ 'Stage1DiffCalc out of range: '+ UUT.RTZVals.Stage1DiffCalc.ToString + #13;
      end;
  end;   //end case
  if EM <> '' then
    begin
      UUT.PassFailStatus := 'FAIL';    //There was an error, so CAL fails.
      UUT.UUTReady := False;  //Need to set this to communicate back to thread that UUT is no longer ready.
      MemMsg('CALIBRATION FAILED- Error(s) occured: '+#13 + EM);
      frmMain.sbStatus.Panels[1].Text := 'Calilbration Failed.';
      frmMain.ConfigCalAccess;    //UUT status has changed, so update buttons accordingly.
    end
    else
      UUT.UUTReady := True;
end;

(*******************************************************************************
 CheckLeakTest: This procedure configures valves, indicator lights appropriately
                  if the leak test fails.
******************************************************************************)
procedure CheckLeakTest(state: TLeakState);
var
  EM: string;
begin
  EM := '';   //initialize
  case state of
    lsStabilize:
      begin
        if not (UUT.PresCurrent > (cfgParams.SystemPresFullPresLowCnfg)) then
          EM := 'Leak test stabilization failure. Pressure:  '+
              (UUT.PresCurrent).ToString(ffFixed, 15,3) + ' PSI';
      end;
    lsDecay:
      begin
        if UUT.PressLeakCalc > (cfgParams.LeakHighCnfg /4) then
          EM:= 'Leak rate this cycleversion > LeakHighCnfg/4: +' +
                UUT.PressLeakCalc.ToString(ffFixed,15,3) +
                'PSI/MIN';
      end;
    lsFinal:
      begin
        if not( UUT.PressLeakCalc <= cfgParams.LeakHighCnfg) then
          EM := 'Leak rate exceeded specification: '+
                UUT.PressLeakCalc.ToString(ffFixed,15,3) +
                'PSI/MIN';
      end;
  end;
  if EM <> '' then
    begin
      if state = lsFinal then
      begin
        UUT.PassFailStatus := 'FAIL';    //There was an error, so CAL fails.
        UUT.LeakTestOK := False;  //Need to set this to communicate back to thread that UUT is no longer ready.
        frmMain.ConfigCalAccess;    //UUT status has changed, so update buttons accordingly.
        frmMain.cbHighPress.Checked := False;  //relase high pressure.
        frmMain.cbVent.Checked := False;    //Allow to vent
        frmMain.cbSeal.Checked := False;    //Release seal on syringe
        TH.SetFail(True);
        TH.SetPass(False);
        TH.SetTIP(False);
        MemMsg('CALIBRATION FAILED- Error(s) occured: '+#13 + EM);
        frmMain.sbStatus.Panels[1].Text := 'Calilbration Failed.';
        frmMain.lblLeakRate.Visible := False;
        frmMain.lblDecayVal.Visible := False;
      end
      else
        MemMsg('Warning: '+ EM);
    end
      else
        UUT.LeakTestOK := True;
end;

(*******************************************************************************
 CheckFinalCalcs: This procedure verifies that the final A1 calculation and
                  assoicated calculations are in spec.
******************************************************************************)
procedure CheckFinalCalcs;
var
  EM: string; dTmp: double;
begin
  EM := '';   //initialize
  if not (UUT.A1Calc <= cfgParams.SlopeMaxCnfg) then
    EM := EM + 'A1Calc out of acceptable range: '+UUT.A1Calc.ToString(ffFixed,15,3);
  //Now calcualte and check the ModelHigh and ModelLow calcs, as well as hysteresis
  //and check that values are in range.
  dTmp := (UUT.A1Calc/1024)* cfgParams.PresA2DRailedMaxCnfg + UUT.C1Calc - cfgParams.RZWindowCnfg;
  if not(dTmp > cfgParams.DsplMaxAtmBarCnfg) then
    EM := EM + 'ModelHighCalc out of range: '+dTmp.ToString(ffFixed, 15, 3);
  dTmp := (UUT.A1Calc/1024) * cfgParams.PresA2DRailedMinCnfg + UUT.C1Calc + cfgParams.RZWindowCnfg;
  if not (dTmp < cfgParams.DsplMinCnfg) then
    EM := EM + 'ModelLowCalc out of range: '+dTmp.ToString(ffFixed,15,3);
  dTmp := 100*((UUT.RTZVals.PresADAvg - UUT.ZeroVals.PresADAvg)* (UUT.A1Calc/1024)) / cfgParams.DsplMaxAtmBarCnfg;
  if not((dTmp >= (cfgParams.HysteresisMaxCnfg*-1)) and (dTmp <= cfgParams.HysteresisMaxCnfg)) then
    EM := EM + 'Hysteresis calculation of of range: '+dTmp.ToString(ffFixed,15,3);
  //Now update pass/Fail results and return to thread.
  if EM <> '' then
    begin
      UUT.PassFailStatus := 'FAIL';    //There was an error, so CAL fails.
      UUT.UUTReady := False;  //Need to set this to communicate back to thread that UUT is no longer ready.
      MemMsg('CALIBRATION FAILED- Error(s) occured: '+#13 + EM);
      frmMain.ConfigCalAccess;    //UUT status has changed, so update buttons accordingly.
    end
    else
      UUT.UUTReady := True;
end;


(*******************************************************************************
 CHeckSN: Check that all information written to the UUT as the SN is read back
          correctly.
******************************************************************************)
procedure CheckSN;
var
  EM: string;  i,j: Integer;
begin
  EM := '';
  //First check the base 7 digits of the SN
  j := Low(UUT.bSNsent);
  for i := Low(UUT.bSNsent) to High(UUT.bSNsent) do
    begin
      if not(UUT.bSNsent[i] = UUT.bSNRcv[i]) then
      EM := 'Error occured in SN byte ' + i.ToString +'. Value Expected: '+
            UUT.bSNsent[i].toString + ' Value Found: '+UUT.bSNRcv[i].toString;
      inc(j,2);   //skip past even "XOR" bytes in received SN array.
    end;
  //now check the SN Sum byte
  if not UUT.bSum = UUT.bSNRcv[15] then
    EM := 'Error occured in SN sum byte. Value Expected: '+UUT.bSum.ToString +
          'Value Received: '+ UUT.bSNRcv[15].toString;
  //now finally check the version information
  if not UUT.VersionUUT = cfgParams.VersionCnfg then
    EM := 'Error occured- Incorrect Version. Expected: '+cfgParams.VersionCnfg.ToString +
          ' Received: '+UUT.VersionUUT.ToString;
  if EM <> '' then
    begin
      UUT.PassFailStatus := 'FAIL';    //There was an error, so CAL fails.
      UUT.UUTReady := False;  //Need to set this to communicate back to thread that UUT is no longer ready.
      MemMsg('CALIBRATION FAILED- '+#13 + EM);
      frmMain.ConfigCalAccess;    //UUT status has changed, so update buttons accordingly.
    end
    else
      UUT.UUTReady := True;
end;


(*******************************************************************************
 FullResetTester: Clears all of the relays and indicator lights on the test head,
                   and also calls ResetGui.
******************************************************************************)
procedure FullResetTester;
begin
  TH.SetSeal(True);
  Sleep(100);
  TH.SetSeal(False);
  TH.SetVent(True);
  Sleep(100);
  TH.SetVent(False);
  TH.SetHighLow(True);
  Sleep(100);
  TH.SetHighLow(False);
  TH.SetFastest(True);
  Sleep(100);
  TH.SetFastest(False);
  Sleep(100);
  TH.SetTip(True);
  Sleep(100);
  TH.SetTip(False);
  TH.SetSens(True);
  Sleep(100);
  TH.SetSens(False);
  TH.SetPass(True);
  Sleep(100);
  TH.SetPass(False);
  TH.SetFail(True);
  Sleep(100);
  TH.SetFail(False);
  ResetGui;
end;

(*******************************************************************************
 ResetGui: Clears all of the variable values written to grids, labels, memos
           etc. that occur during a normal program/cal cycle.
******************************************************************************)
procedure ResetGui;
var i: Integer;
begin
  frmMain.Memo1.Lines.Clear;
  frmMain.FP5Term.ClearScreen;
  for i := 1 to frmMain.sgADData.RowCount-1 do
    frmMain.sgADData.Cells[1,i] := '';
  for i := 1 to frmMain.sgADData.RowCount-1 do
    frmMain.sgADData.Cells[2,i] := '';
  for i := 1 to frmMain.sgADData.RowCount-1 do
    frmMain.sgADData.Cells[3,i] := '';
  for i := 0 to frmMain.sgSN.RowCount do
    frmMain.sgSN.Cells[1,i] := '';
  for i := 0 to frmMain.sgUUTParameters.RowCount do
    frmMain.sgUUTParameters.Cells[1,i] := '';
  frmMain.edSN.Text := '';
  frmMain.sbStatus.Panels[1].Text := '';
  frmMain.lblPress.Caption := '';
  frmMain.lblDecayVal.Caption := '';
  frmMain.lblLeakRate.Caption:= '';
end;


end.
